package com.template.project.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author xs
 */
@Aspect
@Configuration
@Order(1)
public class WebLogAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)")
    public void webLog() {
    }

    @Around("webLog()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.nanoTime();
        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            // 如果没有请求上下文，则可能是在异步线程或其他非请求环境中，跳过日志记录
            logger.warn("No request context available for method: {}.{} - skipping logging",
                    joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
            return joinPoint.proceed();
        }
        HttpServletRequest request = attributes.getRequest();
        // 执行目标方法
        Object result;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            logger.error("URL: {}, Method: {}, IP: {}, Arguments: {}, timeTaken: {}ms", request.getRequestURL(), request.getMethod(),
                    request.getRemoteAddr(), sanitizeArgs(joinPoint.getArgs()), (System.nanoTime() - startTime) / 1e6d);
            throw e;
        }
        // 计算方法执行时间
        long timeTaken = System.nanoTime() - startTime;
        // 记录请求内容执行时间
        logRequest(joinPoint, request, timeTaken);
        return result;
    }

    private void logRequest(JoinPoint joinPoint, HttpServletRequest request, long timeTaken) {
        // 记录下请求内容
        if (logger.isInfoEnabled()) {
            logger.info("URL: {}, Method: {}, IP: {}, Arguments: {}, timeTaken: {}ms", request.getRequestURL(), request.getMethod(),
                    request.getRemoteAddr(), sanitizeArgs(joinPoint.getArgs()), timeTaken / 1e6d);
        }
    }

    private String sanitizeArgs(Object[] args) {
        StringBuilder sanitizedArgs = new StringBuilder("[");
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                continue;
            }
            if (arg instanceof MultipartFile) {
                sanitizedArgs.append(((MultipartFile) arg).getOriginalFilename());
            } else {
                sanitizedArgs.append(arg);
            }
            if (i < args.length - 1) {
                sanitizedArgs.append(", ");
            }
        }
        sanitizedArgs.append("]");
        return sanitizedArgs.toString();
    }
}
